#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>



SDL_Window *win = NULL; //一些全局变量  窗口
SDL_Renderer *rdr = NULL;  //渲染器

typedef struct {
    int x; // 棋子横坐标   x和y为相对于棋盘的坐标。最左上角为（0，0）
    int y; // 棋子纵坐标
    int kind; // 棋子种类 0为黑，1为白,其余为无
} ChessPiece;
ChessPiece chessPieces[365];  //定义一个存储棋子信息的结构体。大小设置得比实际19×19=361大一些
ChessPiece chessPreview[1]; //仅存储预览棋子。颜色不为黑白

typedef struct{
    int x;
    int y;
    int kind;
    int circumstance;  //某个棋子的状态 0：待判断，1：依靠周围的棋子活
}ChessToJudge;  //暂时用来判断棋子死活的结构体。里面装的是暂时需要判断死活的一片棋子
ChessToJudge chessToJudge[365];  //记得每次判断之后暂时清空

int preview =0;  //用户是否正在预览。0为否，其余为是（默认是1）

int myChessKind = 0; //宏定义该用户下的棋是黑棋
int enemyChessKind = 1; //宏定义对手的棋子是白棋

int startX = 150; //棋盘的x0位置
int startY = 130; //棋盘的y0位置

#define SERVER_PORT 8080  //服务器端口号

#define SERVER_IP  "192.168.111.250"  //服务器ip地址

int socketfd;  //客户端的socket，定义后应一直维持不变。


void fillColor(){ //填满窗口颜色  （如果需要窗口颜色变化，这个地方可以改成自己传rgb值
    SDL_SetRenderDrawColor(rdr,153,204,255,200); //设置渲染颜色。前三个数字是rgb，最后一个好像是透明度，范围均为0-255
    SDL_RenderClear(rdr); //用上一行定义的天蓝色清屏（填满整个窗口）
    printf("已为窗口设置颜色\n");
}

void init(){ //初始化

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { //初始化
        SDL_Log("Init failed: %s", SDL_GetError());
    }

    win = SDL_CreateWindow("我是傻逼", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 800,
                           SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);//创建窗口
    if (NULL == win) {  //判断窗口是否创建成功
        SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
    }

    rdr = SDL_CreateRenderer(win,-1,0);  //创建与窗口关联的渲染器
    if (NULL == rdr) {  //判断渲染器是否创建成功
        SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
    }
    printf("已初始化窗口和渲染器\n");

}

void deinit(){  //回收/销毁

    SDL_DestroyRenderer(rdr); //销毁渲染器
    SDL_DestroyWindow(win); //销毁窗口
    printf("已销毁窗口和渲染器\n");
}

void changeItoS(int a, int b, char result[]) {  //将坐标转化为字符串
    char str_a[3], str_b[3];

    sprintf(str_a, "%02d", a);  // 将a和b转换为字符串，并添加前导零（如果需要）
    sprintf(str_b, "%02d", b);

    result[0]=str_a[0];
    result[1]=str_a[1];
    result[2]=str_b[0];
    result[3]=str_b[1];
    result[4] = '\0'; // 添加字符串结束符
}

void changeStoI(char c[], int *num1, int *num2) {  //将客户端传来的字符串转化为坐标
    *num1 = (c[0] - '0') * 10 + (c[1] - '0');
    *num2 = (c[2] - '0') * 10 + (c[3] - '0');
}

void initChessPieces() {// 初始化棋子数组（初始化内容均为-1，代表该位置无有效棋子）  x和y为相对于棋盘的坐标
    int i;
    for (i = 0; i < 365; i++) {
        chessPieces[i].x = -1;
        chessPieces[i].y = -1;
        chessPieces[i].kind = -1;
    }
    printf("已初始化棋子数组\n");

    chessPreview[0].x = 50;
    chessPreview[0].y = 50;
    chessPreview[0].kind = 50;
    printf("已初始化棋子预览数组\n");
}

void drawCircle(SDL_Renderer *renderer, int x, int y, int radius ,int r ,int g ,int b) {  //画圆。参数分别是：渲染器、圆心横纵坐标、半径、rgb值

    SDL_SetRenderDrawColor(renderer,r,g,b,255);

    int x_pos = 0;
    int y_pos = radius;
    int decision_over_2 = 1 - radius;

    while(y_pos >= x_pos) {
        SDL_RenderDrawLine(renderer, x + x_pos, y + y_pos, x - x_pos, y + y_pos); //根据圆心对称的两点连线
        SDL_RenderDrawLine(renderer, x + y_pos, y + x_pos, x - y_pos, y + x_pos);
        SDL_RenderDrawLine(renderer, x + x_pos, y - y_pos, x - x_pos, y - y_pos);
        SDL_RenderDrawLine(renderer, x + y_pos, y - x_pos, x - y_pos, y - x_pos);


        if(decision_over_2 <= 0) {
            decision_over_2 += 2 * x_pos + 3;
        } else {
            decision_over_2 += 2 * (x_pos - y_pos) + 5;
            y_pos--;
        }
        x_pos++;
    }
}

void drawBoard(){ //画棋盘。因为棋盘的状态和位置都是固定的，所以不传参数

    SDL_SetRenderDrawColor(rdr,240,230,190,255);//定义棋盘颜色
    SDL_Rect rect = {(startX-30),(startY+15-30),600,600}; //在屏幕内绘制一个矩形（棋盘） 四个参数分别为左上角坐标和棋盘大小
    SDL_RenderFillRect(rdr,&rect);

    SDL_SetRenderDrawColor(rdr,0,0,0,255); //黑色线条，不透明。作为棋盘格子
    int distance = 30; //棋盘格子的行列间距
    int i;
    for(i=0 ;i<19 ;i++){ //画横线

        SDL_RenderDrawLine(rdr,startX,(startY+15+(i*30)),(startX+540),(startY+15+(i*30)));  //划线。前两个数、后两个数为线的两个端点的xy坐标
    }
    for(i=0 ;i<19 ;i++){ //画竖线

        SDL_RenderDrawLine(rdr,(startX+(i*30)),startY+15,startX+(i*30),(startY+15+540));
    }

    drawCircle(rdr,startX+90,startY+15+90,3,0,0,0); //画星位
    drawCircle(rdr,startX+90,startY+15+270,3,0,0,0);
    drawCircle(rdr,startX+90,startY+15+450,3,0,0,0);
    drawCircle(rdr,startX+270,startY+15+90,3,0,0,0);
    drawCircle(rdr,startX+270,startY+15+270,3,0,0,0);
    drawCircle(rdr,startX+270,startY+15+450,3,0,0,0);
    drawCircle(rdr,startX+450,startY+15+90,3,0,0,0);
    drawCircle(rdr,startX+450,startY+15+270,3,0,0,0);
    drawCircle(rdr,startX+450,startY+15+450,3,0,0,0);

    SDL_RenderPresent(rdr); //呈现渲染
}

void drawUI(){  //绘制界面的其他组件  包括图形和文字

    drawCircle(rdr,810,550,20,0,0,0); //黑棋标识
    SDL_SetRenderDrawColor(rdr,0,0,0,255); //定义P1
    SDL_Rect recta1 = {860,530,4,40};  //画p
    SDL_Rect recta2 = {864,530,11,4};
    SDL_Rect recta3 = {864,546,11,4};
    SDL_Rect recta4 = {875,530,4,20};
    SDL_Rect recta5 = {899,530,4,40};  //画1
    SDL_RenderFillRect(rdr,&recta1);
    SDL_RenderFillRect(rdr,&recta2);
    SDL_RenderFillRect(rdr,&recta3);
    SDL_RenderFillRect(rdr,&recta4);
    SDL_RenderFillRect(rdr,&recta5);

    drawCircle(rdr,810,250,20,255,255,255);  //白棋标识
    SDL_SetRenderDrawColor(rdr,255,255,255,255); //定义P2
    SDL_Rect rectb1 = {860,530-300,4,40};  //画p
    SDL_Rect rectb2 = {864,530-300,11,4};
    SDL_Rect rectb3 = {864,546-300,11,4};
    SDL_Rect rectb4 = {875,530-300,4,20};
    SDL_Rect rectb5 = {899,230,14,4};  //画2
    SDL_Rect rectb6 = {899,248,14,4};
    SDL_Rect rectb7 = {899,266,14,4};
    SDL_Rect rectb8 = {909,234,4,14};
    SDL_Rect rectb9 = {899,252,4,14};
    SDL_RenderFillRect(rdr,&rectb1);
    SDL_RenderFillRect(rdr,&rectb2);
    SDL_RenderFillRect(rdr,&rectb3);
    SDL_RenderFillRect(rdr,&rectb4);
    SDL_RenderFillRect(rdr,&rectb5);
    SDL_RenderFillRect(rdr,&rectb6);
    SDL_RenderFillRect(rdr,&rectb7);
    SDL_RenderFillRect(rdr,&rectb8);
    SDL_RenderFillRect(rdr,&rectb9);

    SDL_SetRenderDrawColor(rdr,255,215,128,255); //定义用户可互动按钮颜色

    SDL_Rect rect = {810,340,180,120};  //用户点击确定，以便于落子
    SDL_Rect rect2 = {1000,50,100,60};  //投降按钮

    SDL_RenderFillRect(rdr,&rect);
    SDL_RenderFillRect(rdr,&rect2);

    SDL_SetRenderDrawColor(rdr,197,249,187,255); //定义对号颜色
    int i ;
    for(i = 0 ;i <40 ;i++){
        SDL_RenderDrawLine(rdr,(860+0.5*i),(390+0.5*i),(880+0.5*i),(430+0.5*i));  //画对号
        SDL_RenderDrawLine(rdr,(880+0.5*i),(430+0.5*i),(920+0.5*i),(350+0.5*i));
    }

    SDL_SetRenderDrawColor(rdr,0,0,0,255); //画白旗投降
    SDL_Rect rect3 = {1025,55,4,50};
    SDL_RenderFillRect(rdr,&rect3);
    SDL_SetRenderDrawColor(rdr,255,255,255,255);
    SDL_Rect rect4 = {1029,55,40,26};
    SDL_RenderFillRect(rdr,&rect4 );

    SDL_RenderPresent(rdr); //呈现渲染
    printf("已绘制其余组件\n");
}

void addChess(int x, int y, int kind) {  //在某方落子的时候，向棋子数组内添加新的棋子（有效棋子）  x和y为相对于棋盘的坐标
    int i;
    for (i = 0; i < 365; i++) {
        if (chessPieces[i].x == -1 && chessPieces[i].y == -1 && chessPieces[i].kind == -1) { //从头找，找到一个没有棋子的位置
            chessPieces[i].x = x;
            chessPieces[i].y = y;
            chessPieces[i].kind = kind ;
            printf("已向数组添加新棋子，坐标为:");
            printf("%d,%d,%d\n",x,y,kind);
            break;
        }
    }
}

void delChess(int x, int y){  //某个棋子死，在数组中把它重置掉  x和y为相对于棋盘的坐标
    int i;
    for (i = 0; i < 365; i++) {
        if (chessPieces[i].x == x && chessPieces[i].y == y) { //从头找，找到该棋子
            chessPieces[i].x = -1;
            chessPieces[i].y = -1;
            chessPieces[i].kind = -1 ;
            printf("该棋子已死,棋子坐标:\");\n"
                   "            printf(\"%d,%d,%d\\n",x,y);
            break;
        }
    }
}

void eraseOneChess( int x , int y){  //从棋盘上擦除掉某个棋子的图片(当有棋子死掉，或者预览棋子位置的时候使用) x和y为相对于棋盘的坐标

    drawCircle(rdr,(startX+30*x),(startY+30*y),14,240,230,190);  //在棋子位置画一个和棋盘同样颜色的圆

    SDL_SetRenderDrawColor(rdr,0,0,0,255); //将颜色设置为黑色。之后的两行为补全棋盘网格


    if((x==3 && y==3) || (x==3 && y==9) || (x==3 && y==15) || (x==9 && y==3) || (x==9 && y==9) || (x==9 && y==15) || (x==15 && y==3) || (x==15 && y==9) || (x==15 && y==15)){  //在星位上
        drawCircle(rdr,(startX+30*x),(startY+30*y),3,0,0,0); //画星位
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x+15),(startY+30*y));  //画横线
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y+15));  //画竖线
    }else if(x==0 && y>0 && y<18){  //在左边界
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y+15));
    }else if(x==18 && y>0 && y<18){  //在右边界
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y+15));
    }else if(y==0 && x>0 && x<18){  //在上边界
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x),(startY+30*y+15));
    }else if(y==18 && x>0 && x<18){  //在下边界
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y));
    }else if(x==0 && y==0){  //在左上角
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x),(startY+30*y+15));
    }else if(x==0 && y==18){  //在左下角
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y));
    }else if(x==18 && y==0){  //在右上角
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y),(startX+30*x),(startY+30*y+15));
    }else if(x==18 && y==18){  //在右下角
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y));
    }
    else{  //其余正常的格子
        SDL_RenderDrawLine(rdr,(startX+30*x-15),(startY+30*y),(startX+30*x+15),(startY+30*y));
        SDL_RenderDrawLine(rdr,(startX+30*x),(startY+30*y-15),(startX+30*x),(startY+30*y+15));
    }

    SDL_RenderPresent(rdr); //呈现渲染
    printf("已在棋盘上擦除棋子,坐标为：%d，%d\n",x,y);
}

void drawOneChess( int x , int y , int kind){  //加载(画)一个单独的棋子  x和y为相对于棋盘的坐标 (这个棋子是对弈双方新下的）

    if(kind == 0){  //黑棋
        drawCircle(rdr,(startX+30*x),(startY+30*y),13,0,0,0); //下黑棋
    }
    else if(kind == 1){  //白棋
        drawCircle(rdr,(startX+30*x),(startY+30*y),13,255,255,255);  //下白棋
    }

    SDL_RenderPresent(rdr); //呈现渲染
    printf("已尝试画一个棋子，xy坐标和种类为：");
    printf("%d,%d,%d\n",x,y,kind);

}

void previewOneChess(int x , int y){  //预览(现在要下的）棋子  x和y为相对于棋盘的坐标

    if (preview ==0){  //本回合还没预览过棋子

        chessPreview[0].x = x;  //暂时存储预览位置
        chessPreview[0].y = y;
        preview = 1;  //设置为已有预览
        drawCircle(rdr,(startX+30*x),(startY+30*y),12,0,121,158); //在对应位置画蓝色棋子，作为预览

    }else{  //本回合已经预览过棋子了

        eraseOneChess(chessPreview[0].x , chessPreview[0].y); //擦除旧预览位置上的红色棋子
        chessPreview[0].x = x;  //暂时存储新预览位置
        chessPreview[0].y = y;
        drawCircle(rdr,(startX+30*x),(startY +30*y),12,0,121,158); //在对应位置画红色棋子，作为预览
    }

    printf("已尝试更新预览位置，坐标为：%d,%d\n",x,y);
    SDL_RenderPresent(rdr); //呈现渲染

}

void initChessArray(ChessToJudge *array, int size) {  //传进来一个数组，内容全变-1
    int i = 0;
    for (i; i < size; ++i) {
        array[i].x = -1;
        array[i].y = -1;
        array[i].kind = -1;
        array[i].circumstance = -1;
    }
}

void initChessToJudge() {// 初始化或者说清空存储需要判断死活的棋子的数组（初始化内容均为-1，代表该位置无有效棋子）  x和y为相对于棋盘的坐标
    int i;
    for (i = 0; i < 365; i++) {
        chessToJudge[i].x = -1;
        chessToJudge[i].y = -1;
        chessToJudge[i].kind = -1;
        chessToJudge[i].circumstance = -1;
    }
}

void delChessFromArray(ChessToJudge *array, int size){   //传入数组，删除棋子

    int i = 0;
    for (i; i < size; ++i) {
        if(array[i].x != -1 && array[i].y != -1){
            delChess(array[i].x , array[i].y);
        }
    }

}

void addDifferentChessToStruct(int x, int y,int kind){  //判断结构体数组内是否有在这个位置的棋子，如果没有则加入
    int i = 0;
    int haveOrNot = 0;
    for(i;i<sizeof(chessToJudge);i++) {
        if (chessToJudge[i].x == x && chessToJudge[i].y == y) {  //已经有了
            haveOrNot = 1;
            break; //退出循环
        }
    }

    if(haveOrNot == 0){
        int j = 0;
        for(j;j<sizeof(chessToJudge);j++){  //从头找，找到一个还没放棋子的地方，给加进去
            if(-1==chessToJudge[i].x && -1==chessToJudge[i].y){
                chessToJudge[i].x = x;
                chessToJudge[i].y = y;
                chessToJudge[i].kind = kind;
                chessToJudge[i].circumstance = 0; //刚加进去没判断的时候是0
            }else{
                printf("报错：临时存储判断死活棋子的结构体数组chessToJudge已满，请检查问题\n");
            }
        }
    }

}

int enemyOrFriend(int x , int y , int myKind){  //判断座标处状态 传递内容为需要判断的地方的坐标。kind为当前棋子自己的类别

    int i = 0;  //用于循环
    int condition = 0;  //返回值。表示该座标处状态 0为空（有气，直接活），1为同色（需要继续判断同色棋），2为异色或边界（这两种情况都是没气的）
    int enemyKind = -1;  //传入棋子kind的敌对方kind
    if(myKind == 0){
        enemyKind = 1;
    }else{
        enemyKind = 0;
    }

    if( x<=0 || y<=0 || x>=18 || y>=18) {   //是边界

        condition = 2;

    }else{

        for(i; i<sizeof(chessPieces); i++){    //开始判断座标处状态

            if (chessPieces[i].kind == enemyKind &&  x == chessPieces[i].x && y == chessPieces[i].y){  //座标处异色棋

                condition = 2;
                break;

            }else if(chessPieces[i].kind == myKind &&  x == chessPieces[i].x && y == chessPieces[i].y){  //同色棋

                condition = 1;
                break;

            }else{  //该位置没有棋子

                condition = 0;
                break;
            }
        }
    }

    return condition;

}

void judgeDieorNot(int *dieOrNot){  //判断（由某个棋子开始的）结构体内，一个/一片棋子的死活  （刚传进来的时候，数组内只有一个状态0的棋子） int变量0是活，1是死

    int i = 0;  //循环
    *dieOrNot = 1;  //先假设这片棋是死的
    for(i ; i<sizeof(chessToJudge) ; i++){

        if(chessToJudge[i].circumstance == 0){  //数组中有待判断的棋子
            int thisX = chessToJudge[i].x;  //当前要判断的棋子坐标和种类
            int thisY = chessToJudge[i].y;
            int thisKind = chessToJudge[i].kind;
            int up = enemyOrFriend(thisX , (thisY-1) , thisKind);   //对该棋子上下左右的坐标进行判断
            int down = enemyOrFriend(thisX , (thisY+1) , thisKind);
            int left = enemyOrFriend((thisX-1) , thisY , thisKind);
            int right = enemyOrFriend((thisX+1) , (thisY-1) , thisKind);

            if(2==up && 2==down && 2==left &&2==right){  //仅仅适用于单个棋子的情况。全是2，这个棋其实已经死掉了
                chessToJudge[i].circumstance = 1;  //这个子自己活不了（其实是这个单子已经死了）
                break;
            }else{
                if(0==up || 0==down || 0==left || 0==right){  //周围有气，这块棋直接活了,也不用继续判断了

                    *dieOrNot = 0;
                    initChessToJudge();  //再次把判断用的棋子数组清零。这样当函数返回值是0的时候，调用它的函数可以直接得到一个初始化的、没有任何棋子内容的数组，来表示没有相关棋子死亡
                    break;

                }else{   //周围除了异色、边界只有同色。那就找到所有同色，然后把数组中还没有的坐标加入数组,并把自己的状态设为1（已经判断完了，自己活不了，靠别人活）。当某片死棋只剩下最后一个这样的棋需要判断时，判断完了以后这个结构体数组就没有新添加了。等到下次循环的时候，这片棋就直接判断为死
                    if(1==up){
                        addDifferentChessToStruct(thisX,(thisY-1),thisKind);
                    }
                    if(1==down){
                        addDifferentChessToStruct(thisX,(thisY+1),thisKind);
                    }
                    if(1==left){
                        addDifferentChessToStruct((thisX-1),thisY,thisKind);
                    }
                    if(i==right){
                        addDifferentChessToStruct((thisX+1),thisY,thisKind);
                    }
                    chessToJudge[i].circumstance = 1; //把自己设置为已判断
                }
            }
        }
    }//如果运行到这个for循环结束的地方，还没有跳出循环，说明结构体数组中已经没有能自己活的棋了
}


int changeForThisPoint(int x , int y , int kind){  //给出由当前这一个点的变化 返回这个棋子组死没死。死就是1，没死是0


    int dieOrNot = 0;  //假设这片棋死没死
    initChessToJudge();  //初始化判断用的结构体数组
    chessToJudge[0].x = x;  //把这个要判断的坐标加入结构体第一号
    chessToJudge[0].y = y;
    chessToJudge[0].kind = kind;
    chessToJudge[0].circumstance = 0;
    judgeDieorNot(&dieOrNot);
    return dieOrNot;
}

void changeForThisStep(int x,int y,int kind){  //处理新下的这一步棋所带来的变化


    int i =0; //循环

    ChessToJudge arraySelf[365];  //把现在的判断数组中的内容赋值给刚建立的数组。如果这个棋子是活的，那么这个结构体数组所有变量都是-1.如果暂时判定死亡，则这个数组中是有实际内容的
    ChessToJudge arrayUp[365];
    ChessToJudge arrayDown[365];
    ChessToJudge arrayRight[365];
    ChessToJudge arrayLeft[365];
    initChessArray(arraySelf , 365);  //初始化这些结构体内容为-1
    initChessArray(arrayUp , 365);
    initChessArray(arrayDown , 365);
    initChessArray(arrayLeft , 365);
    initChessArray(arrayRight , 365);



    int selfKind = kind;  //初始化自己和上下左右棋子的颜色种类。默认和自己相同
    int enemykind = -1;
    int upKind = -1;
    int downKind = -1;
    int rightKind = -1;
    int leftKind = -1;

    int selfDieOrNot = 0;  //初始化自己和上下左右死没死。0是没死，1是死。默认没死
    int upDieOrNot = 0;
    int downDieOrNot = 0;
    int leftDieOrNot = 0;
    int rightDieOrNot = 0;

    if(0==kind){
        enemykind=1;
    }else{enemykind=0;}


    if(x>0 && x<18 && y>0) {  //这步棋上边不为边界
        if(2==enemyOrFriend(x,y-1,kind)){   //如果上方有敌方棋子
            upKind = enemykind;
        }else if(1==enemyOrFriend(x,y-1,kind)){
            upKind = kind;
        }
    }
    if(x>0 && x<18 && y<18){  //这步棋下边不为边界
        if(2==enemyOrFriend(x,y+1,kind)){   //如果上方有敌方棋子
            downKind = enemykind;
        }else if(1==enemyOrFriend(x,y+1,kind)){
            downKind = kind;
        }
    }
    if(y>0 && y<18 && x>0) {  //这步棋右边不为边界
        if(2==enemyOrFriend(x+1,y,kind)){   //如果上方有敌方棋子
            rightKind = enemykind;
        }else if(1==enemyOrFriend(x+1,y,kind)){
            rightKind = kind;
        }
    }
    if(y>0 &&y<18 && x<18) {  //这步棋左边不为边界
        if(2==enemyOrFriend(x-1,y,kind)){   //如果上方有敌方棋子
            leftKind = enemykind;
        }else if(1==enemyOrFriend(x-1,y,kind)){
            leftKind = kind;
        }
    }  //上述4个if结束后，可确定棋子上下左右的情况。空或边界kind为-1，余下kind为实际kind

    selfDieOrNot = changeForThisPoint(x,y,selfKind);  //给有东西的棋子判断死活，然后得到数组 0是没死，1是死
    for (i; i < 365; ++i) {  //循环给它赋值。没再自定义函数，已经比较多了，怕分不清
        arraySelf[i].x = chessToJudge[i].x;
        arraySelf[i].y = chessToJudge[i].y;
        arraySelf[i].kind = chessToJudge[i].kind;
        arraySelf[i].circumstance = chessToJudge[i].circumstance;
    }
    if(upKind != -1){
        upDieOrNot = changeForThisPoint(x,y-1,upKind);
        for (i ; i < 365; ++i) {
            arrayUp[i].x = chessToJudge[i].x;
            arrayUp[i].y = chessToJudge[i].y;
            arrayUp[i].kind = chessToJudge[i].kind;
            arrayUp[i].circumstance = chessToJudge[i].circumstance;
        }
    }
    if(downKind != -1){
        downDieOrNot = changeForThisPoint(x,y+1,downKind);
        for (i; i < 365; ++i) {  //循环给它赋值。没再自定义函数，已经比较多了，怕分不清
            arrayDown[i].x = chessToJudge[i].x;
            arrayDown[i].y = chessToJudge[i].y;
            arrayDown[i].kind = chessToJudge[i].kind;
            arrayDown[i].circumstance = chessToJudge[i].circumstance;
        }
    }
    if(leftKind != -1){
        leftDieOrNot = changeForThisPoint(x-1,y,leftKind);
        for (i; i < 365; ++i) {  //循环给它赋值。没再自定义函数，已经比较多了，怕分不清
            arrayLeft[i].x = chessToJudge[i].x;
            arrayLeft[i].y = chessToJudge[i].y;
            arrayLeft[i].kind = chessToJudge[i].kind;
            arrayLeft[i].circumstance = chessToJudge[i].circumstance;
        }
    }if(rightKind != -1){
        rightDieOrNot = changeForThisPoint(x+1,y,rightKind);
        for (i; i < 365; ++i) {  //循环给它赋值。没再自定义函数，已经比较多了，怕分不清
            arrayRight[i].x = chessToJudge[i].x;
            arrayRight[i].y = chessToJudge[i].y;
            arrayRight[i].kind = chessToJudge[i].kind;
            arrayRight[i].circumstance = chessToJudge[i].circumstance;
        }
    }  //到这里，死掉的数组也已经被赋值了

    int totalDeath = selfDieOrNot+upDieOrNot+downDieOrNot+leftDieOrNot+rightDieOrNot;
    if(0==totalDeath){
        printf("这一步没有棋子死掉\n");
    }else if(1==totalDeath){  //只死了一处
        if(selfDieOrNot == 1){
            delChessFromArray(arraySelf,365);
        }
        if(upDieOrNot == 1){
            delChessFromArray(arrayUp,365);
        }
        if(downDieOrNot == 1){
            delChessFromArray(arrayDown,365);
        }
        if(leftDieOrNot == 1){
            delChessFromArray(arrayLeft,365);
        }
        if(rightDieOrNot == 1){
            delChessFromArray(arrayRight,365);
        }
    }else{  //死了好几处  谁跟这一步的棋一个颜色谁不死

        if(upDieOrNot == 1 && upKind != selfKind){
            delChessFromArray(arrayUp,365);
        }
        if(downDieOrNot == 1 && downKind != selfKind){
            delChessFromArray(arrayDown,365);
        }
        if(leftDieOrNot == 1 && leftKind != selfKind){
            delChessFromArray(arrayLeft,365);
        }
        if(rightDieOrNot == 1 && rightKind != selfKind){
            delChessFromArray(arrayRight,365);
        }
    }


}

void writeMessage(char *message) {   // 向服务器发送信息

    int len = strlen(message);
    printf("客户端尝试向服务器发送信息：%s\n",message);
    write(socketfd, message, len);
    memset(message, 0, sizeof(message));  //清除缓冲区之前的内容
}

void receiveMessage(int sockfd, char *buf, size_t buf_size) {  // 接收服务器信息   转变为int， 存入数组，并显示到棋盘上（完整版：需要加上判断）
    int n = read(sockfd, buf, buf_size - 1);

    if (n > 0) {
        buf[n] = '\0';
        printf("接收到服务器信息: %s\n", buf);
    } else {
        perror("错误!!!");
    }

    int pointX;
    int pointY;
    changeStoI(buf,&pointX,&pointY);  //从返回值的字符串中，截取坐标
    printf("从服务器新传来的对手落子坐标为：%d,%d\n",pointX,pointY);

    addChess(pointX,pointY,enemyChessKind); //向数组中新添加刚接收的棋子，种类是对手的

    changeForThisPoint(pointX,pointY,myChessKind);  //判断接收这一枚对手的棋子的影响

    drawOneChess(pointX , pointY , enemyChessKind);  //暂时把这个棋子直接画到棋盘上

}

void judgeLocation( int x , int y ){  //判断鼠标点击位置是否在可交互位置  x和y为传入的坐标（基于窗口）

    if((x>startX && x<=(startX+540)) && (y>startY && y<=(startY+540))){  //点在棋盘上

        printf("用户点击棋盘\n");
        int relativeX;
        int relativeY;

        relativeX = ((x - startX) + 15) / 30;
        relativeY = ((y - startY) + 15) / 30;

        int k = 0;  //判断点击位置是否已经有棋子
        int i = 0;
        for(i;i<400;i++){
            if((relativeX == chessPieces[i].x) && (relativeY == chessPieces[i].y) && ( -1 != chessPieces[i].kind)){
                k = 1;
                break;
            }
        }
        if(k != 1){
            previewOneChess(relativeX,relativeY); //将预览展示给用户
        }

    }else if((x>810 && x<990) && (y>340 && y<460)){  //点在确定上

        printf("用户点击确认按钮\n");

        addChess(chessPreview[0].x , chessPreview[0].y , myChessKind);  //把当前预览的棋子变为正式的棋子  加入存储已有棋的数组内
        drawOneChess(chessPreview[0].x , chessPreview[0].y , myChessKind);  //图形界面预览位置棋子变化成正式棋子

        preview = 0; //重置预览棋子状态  保证已确定的棋子不会被从屏幕清除

        char message[2048] = "";  //定义一个用来存储刚下的棋子坐标的字符串，之后要把这个字符串传递到服务器

        changeItoS(chessPreview[0].x , chessPreview[0].y , message);  //将坐标转化为字符串

        changeForThisPoint(chessPreview[0].x , chessPreview[0].y , myChessKind); //给出这一步的变化（是否有棋子死亡）

        printf("本次将坐标转化后的字符串内容为：%s\n",message);     //此处有问题。多了个”
        printf("%s\n",message);



        writeMessage(message);  //向客户端发送信息
        printf("客户端已向服务器发送信息\n");

        char buf[2048];  //创建用于接收服务器信息的字符串
        receiveMessage(socketfd, buf, sizeof(buf));
        printf("服务器信息接收完毕，内容为：%s\n",buf);


    }else if((x>1000 && x<1100) && (y>50 && y<110)){  //点在投降上

        printf("法国用户\n");

    }else{  //鼠标未点击有效位置

    }

}

void eventLoop(){  //事件循环函数（暂时为死循环。需要修改。 可以考虑用观察者模式去处理）

    SDL_Event event;

    while(1){
        while(SDL_PollEvent(&event)){

            switch (event.type) {
                case SDL_QUIT:

                    return;

                case SDL_WINDOWEVENT:   //窗口拖动事件

                    if(event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED){
                        printf("窗口已被挪动\n");
                        break;
                    }

                case SDL_MOUSEBUTTONDOWN: {  //发生鼠标点击事件

                    SDL_MouseButtonEvent mouseEvent = event.button;
                    int x = mouseEvent.x;
                    int y = mouseEvent.y;

                    judgeLocation(x,y);  //传入鼠标点击的位置，还有用于网络信息传输的套接字。并进行相应操作
                    break;

                }

                default:

                    break;

            }
        }

    }

}

int main() {

    init(); //初始化窗口和渲染器

    initChessPieces(); //初始化存储棋子的结构体

    fillColor();  //给窗口填满颜色

    drawBoard();  //画出棋盘

    drawUI(); //画出其他交互内容

    printf("界面已初始化完毕\n");


    struct sockaddr_in servaddr;

    socketfd = socket(AF_INET, SOCK_STREAM, 0);  //尝试连接服务器

    memset(&servaddr, '\0', sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT);

    connect(socketfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("客户端socket已初始化完毕\n");


    eventLoop();  //事件循环，监听窗口事件

    close(socketfd );  //关闭socket

    deinit();  //回收和销毁

    SDL_Quit();

    return 0;
}


